<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PKCE OpenID Flow - No Redirects</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
        }
        .container {
            background: white;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
        .header {
            text-align: center;
            margin-bottom: 30px;
            color: #333;
        }
        .step {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            background: #fafafa;
        }
        .step.active {
            border-color: #007bff;
            background: #f0f8ff;
        }
        .step.completed {
            border-color: #28a745;
            background: #f0fff0;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: 600;
            color: #555;
        }
        input[type="text"], input[type="password"] {
            width: 100%;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 14px;
            box-sizing: border-box;
        }
        input[type="text"]:focus, input[type="password"]:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        button {
            background: #007bff;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            margin: 8px 4px;
            transition: background-color 0.2s;
        }
        button:hover { background: #0056b3; }
        button:disabled {
            background: #6c757d;
            cursor: not-allowed;
        }
        button.success {
            background: #28a745;
        }
        button.success:hover {
            background: #218838;
        }
        .token-display {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            word-break: break-all;
            margin: 10px 0;
            border: 1px solid #dee2e6;
            max-height: 200px;
            overflow-y: auto;
        }
        .status {
            margin: 15px 0;
            padding: 12px;
            border-radius: 6px;
            font-weight: 500;
        }
        .status.success { background: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
        .status.error { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
        .status.info { background: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460; }
        .spinner {
            border: 3px solid #f3f3f3;
            border-top: 3px solid #007bff;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            animation: spin 1s linear infinite;
            display: inline-block;
            margin-right: 10px;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .hidden { display: none; }
        .iframe-container {
            border: 2px solid #007bff;
            border-radius: 8px;
            margin: 20px 0;
            background: #f8f9fa;
            padding: 10px;
        }
        .oauth-iframe {
            width: 100%;
            height: 400px;
            border: 1px solid #ddd;
            border-radius: 4px;
            background: white;
        }
        .final-result {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            border-radius: 6px;
            padding: 20px;
            margin-top: 20px;
        }
        .progress {
            display: flex;
            justify-content: space-between;
            margin-bottom: 30px;
        }
        .progress-step {
            flex: 1;
            text-align: center;
            padding: 10px;
            background: #f8f9fa;
            border: 1px solid #dee2e6;
            margin: 0 2px;
            border-radius: 4px;
            font-size: 12px;
        }
        .progress-step.active {
            background: #007bff;
            color: white;
        }
        .progress-step.completed {
            background: #28a745;
            color: white;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🔐 PKCE OpenID Flow</h1>
            <p>Complete OpenID Connect authentication with PKCE using iframe (no page redirects)</p>
        </div>

        <div class="progress">
            <div class="progress-step active" id="step0-progress">0. Config</div>
            <div class="progress-step" id="step1-progress">1. Login</div>
            <div class="progress-step" id="step2-progress">2. Session Token</div>
            <div class="progress-step" id="step3-progress">3. iframe PKCE</div>
            <div class="progress-step" id="step4-progress">4. OAuth Tokens</div>
        </div>

        <!-- Step 0: Configuration -->
        <div class="step active" id="step0">
            <h3>⚙️ Step 0: Okta Configuration</h3>
            <p>Configure your Okta environment settings:</p>
            
            <div class="form-group">
                <label for="oktaDomain">Okta Domain:</label>
                <input type="text" id="oktaDomain" name="oktaDomain" value="dev-09210948.okta.com" required>
                <small style="color: #666; font-size: 12px;">Example: dev-12345678.okta.com or your-company.okta.com</small>
            </div>
            
            <div class="form-group">
                <label for="clientId">Client ID:</label>
                <input type="text" id="clientId" name="clientId" value="0oapcjro7liptyDSN5d7" required>
                <small style="color: #666; font-size: 12px;">Your Okta application's client ID</small>
            </div>
            
            <div class="form-group">
                <label for="redirectUri">Redirect URI:</label>
                <input type="text" id="redirectUri" name="redirectUri" value="http://localhost/okta-auth/iframe-callback.html" required>
                <small style="color: #666; font-size: 12px;">Must match your Okta app configuration</small>
            </div>
            
            <div class="form-group">
                <label for="authServerId">Authorization Server ID:</label>
                <input type="text" id="authServerId" name="authServerId" value="default" required>
                <small style="color: #666; font-size: 12px;">Usually 'default' or custom authorization server ID</small>
            </div>

            <div class="form-group">
                <h4 style="margin-top: 25px; margin-bottom: 15px; color: #555;">📍 Generated Endpoints:</h4>
                <div style="background: #f8f9fa; padding: 15px; border-radius: 6px; border: 1px solid #dee2e6;">
                    <div style="margin-bottom: 10px;">
                        <strong>Base URL:</strong><br>
                        <code id="displayBaseUrl">https://dev-09210948.okta.com</code>
                    </div>
                    <div style="margin-bottom: 10px;">
                        <strong>Authorization Endpoint:</strong><br>
                        <code id="displayAuthEndpoint">https://dev-09210948.okta.com/oauth2/default/v1/authorize</code>
                    </div>
                    <div style="margin-bottom: 10px;">
                        <strong>Token Endpoint:</strong><br>
                        <code id="displayTokenEndpoint">https://dev-09210948.okta.com/oauth2/default/v1/token</code>
                    </div>
                    <div>
                        <strong>Authentication API:</strong><br>
                        <code id="displayAuthApi">https://dev-09210948.okta.com/api/v1/authn</code>
                    </div>
                </div>
            </div>
            
            <button onclick="validateAndSaveConfig()">
                <span id="configSpinner" class="spinner hidden"></span>
                <span id="configText">✅ Validate & Save Configuration</span>
            </button>
            
            <div style="margin-top: 15px;">
                <button onclick="loadPresetConfig('demo')" style="background: #6c757d;">
                    📋 Load Demo Config
                </button>
                <button onclick="loadPresetConfig('production')" style="background: #6c757d;">
                    🏢 Load Production Template
                </button>
            </div>
        </div>

        <!-- Step 1: Login -->
        <div class="step hidden" id="step1">
            <h3>🔐 Step 1: Okta Login</h3>
            <div class="form-group">
                <label for="username">Username or Email:</label>
                <input type="text" id="username" name="username" placeholder="Enter your username or email" required>
            </div>
            
            <div class="form-group">
                <label for="password">Password:</label>
                <input type="password" id="password" name="password" placeholder="Enter your password" required>
            </div>
            
            <button onclick="performLogin()">
                <span id="loginSpinner" class="spinner hidden"></span>
                <span id="loginText">🚀 Login to Okta</span>
            </button>
        </div>

        <!-- Step 2: Session Token Display -->
        <div class="step hidden" id="step2">
            <h3>🎫 Step 2: Session Token Retrieved</h3>
            <p>Successfully authenticated with Okta!</p>
            <div class="token-display" id="sessionTokenDisplay"></div>
            <button onclick="startIframePKCE()" class="success">
                ✅ Continue to iframe PKCE Flow
            </button>
        </div>

        <!-- Step 3: iframe PKCE Flow -->
        <div class="step hidden" id="step3">
            <h3>🖼️ Step 3: iframe PKCE Authorization</h3>
            <p>Using iframe to capture authorization code without page redirect:</p>
            
            <div id="iframeStatus" class="status info">
                <span class="spinner"></span>
                <span>Preparing iframe PKCE flow...</span>
            </div>

            <div class="iframe-container hidden" id="iframeContainer">
                <p><strong>OAuth Authorization in iframe:</strong></p>
                <iframe id="oauthIframe" class="oauth-iframe" src="about:blank"></iframe>
                <div class="status info">
                    <span>🔍 Monitoring iframe for authorization code...</span>
                </div>
            </div>
        </div>

        <!-- Step 4: Final Results -->
        <div class="step hidden" id="finalResults">
            <h3>🎉 Success! Your OAuth Tokens</h3>
            
            <h4>Access Token:</h4>
            <div class="token-display" id="finalAccessToken"></div>
            <button onclick="copyToken('access')">📋 Copy Access Token</button>
            <button onclick="decodeToken('access')">🔍 Decode Access Token</button>
            
            <h4>ID Token:</h4>
            <div class="token-display" id="finalIdToken"></div>
            <button onclick="copyToken('id')">📋 Copy ID Token</button>
            <button onclick="decodeToken('id')">🔍 Decode ID Token</button>
            
            <div class="final-result">
                <h4>🌐 Ready for API Integration!</h4>
                <p><strong>Use this Authorization header:</strong></p>
                <div class="token-display">Authorization: Bearer <span id="tokenForHeader"></span></div>
                <button onclick="copyAuthHeader()">📋 Copy Authorization Header</button>
            </div>
        </div>

        <div id="decodedTokens" class="step hidden">
            <h3>🔍 Decoded Token Information</h3>
            <div class="token-display" id="decodedDisplay"></div>
        </div>

        <div id="globalStatus" class="status info hidden">
            <span id="globalStatusText"></span>
        </div>
    </div>

    <script>
        // Okta Configuration (will be populated from user input)
        let oktaConfig = {
            domain: '',
            clientId: '',
            redirectUri: '',
            baseUrl: '',
            authServerId: '',
            authEndpoint: '',
            tokenEndpoint: '',
            authApiEndpoint: ''
        };

        // Global state
        let currentStep = 0;
        let sessionToken = null;
        let pkceParams = {};
        let tokens = { accessToken: null, idToken: null };
        let iframeMonitorInterval = null;

        // Step 0: Configuration Management
        function updateEndpointDisplays() {
            const domain = document.getElementById('oktaDomain').value;
            const authServerId = document.getElementById('authServerId').value;
            
            const baseUrl = `https://${domain}`;
            const authEndpoint = `${baseUrl}/oauth2/${authServerId}/v1/authorize`;
            const tokenEndpoint = `${baseUrl}/oauth2/${authServerId}/v1/token`;
            const authApiEndpoint = `${baseUrl}/api/v1/authn`;
            
            document.getElementById('displayBaseUrl').textContent = baseUrl;
            document.getElementById('displayAuthEndpoint').textContent = authEndpoint;
            document.getElementById('displayTokenEndpoint').textContent = tokenEndpoint;
            document.getElementById('displayAuthApi').textContent = authApiEndpoint;
        }

        function loadPresetConfig(preset) {
            if (preset === 'demo') {
                document.getElementById('oktaDomain').value = 'dev-09210948.okta.com';
                document.getElementById('clientId').value = '0oapcjro7liptyDSN5d7';
                document.getElementById('redirectUri').value = 'http://localhost/okta-auth/iframe-callback.html';
                document.getElementById('authServerId').value = 'default';
            } else if (preset === 'production') {
                document.getElementById('oktaDomain').value = 'your-company.okta.com';
                document.getElementById('clientId').value = 'your-client-id-here';
                document.getElementById('redirectUri').value = 'https://your-app.com/callback';
                document.getElementById('authServerId').value = 'default';
            }
            updateEndpointDisplays();
            showGlobalStatus(`✅ ${preset} configuration template loaded`, 'success');
        }

        async function validateAndSaveConfig() {
            const domain = document.getElementById('oktaDomain').value.trim();
            const clientId = document.getElementById('clientId').value.trim();
            const redirectUri = document.getElementById('redirectUri').value.trim();
            const authServerId = document.getElementById('authServerId').value.trim();

            // Validation
            if (!domain || !clientId || !redirectUri || !authServerId) {
                showGlobalStatus('Please fill in all configuration fields', 'error');
                return;
            }

            // Validate domain format
            if (!domain.includes('.') || domain.startsWith('http')) {
                showGlobalStatus('Domain should be just the hostname (e.g., dev-12345678.okta.com)', 'error');
                return;
            }

            // Validate redirect URI format
            try {
                new URL(redirectUri);
            } catch (e) {
                showGlobalStatus('Redirect URI must be a valid URL', 'error');
                return;
            }

            setConfigLoading(true);
            showGlobalStatus('Validating Okta configuration...', 'info');

            try {
                // Build configuration
                oktaConfig = {
                    domain: domain,
                    clientId: clientId,
                    redirectUri: redirectUri,
                    baseUrl: `https://${domain}`,
                    authServerId: authServerId,
                    authEndpoint: `https://${domain}/oauth2/${authServerId}/v1/authorize`,
                    tokenEndpoint: `https://${domain}/oauth2/${authServerId}/v1/token`,
                    authApiEndpoint: `https://${domain}/api/v1/authn`
                };

                // Test connectivity to Okta (optional - just check if domain resolves)
                const testResponse = await fetch(`${oktaConfig.baseUrl}/.well-known/openid_configuration`, {
                    method: 'GET',
                    mode: 'cors'
                }).catch(() => null);

                if (testResponse && testResponse.ok) {
                    const wellKnown = await testResponse.json();
                    showGlobalStatus('✅ Okta configuration validated successfully!', 'success');
                    
                    // Optionally verify endpoints match
                    if (wellKnown.authorization_endpoint !== oktaConfig.authEndpoint) {
                        showGlobalStatus(`⚠️ Warning: Authorization endpoint mismatch. Expected: ${wellKnown.authorization_endpoint}`, 'info');
                    }
                } else {
                    showGlobalStatus('⚠️ Could not validate Okta endpoints, but configuration saved', 'info');
                }

                // Move to next step
                updateProgress(1);
                showStep(1);
                showGlobalStatus('Configuration saved! Ready to login.', 'success');

            } catch (error) {
                showGlobalStatus(`Configuration validation error: ${error.message}`, 'error');
            } finally {
                setConfigLoading(false);
            }
        }

        function setConfigLoading(loading) {
            const spinner = document.getElementById('configSpinner');
            const text = document.getElementById('configText');
            const button = document.querySelector('#step0 button');
            
            if (loading) {
                spinner.classList.remove('hidden');
                text.textContent = 'Validating...';
                button.disabled = true;
            } else {
                spinner.classList.add('hidden');
                text.textContent = '✅ Validate & Save Configuration';
                button.disabled = false;
            }
        }

        // Add event listeners for real-time endpoint updates
        document.addEventListener('DOMContentLoaded', function() {
            const domainInput = document.getElementById('oktaDomain');
            const authServerInput = document.getElementById('authServerId');
            
            domainInput.addEventListener('input', updateEndpointDisplays);
            authServerInput.addEventListener('input', updateEndpointDisplays);
            
            // Initialize displays
            updateEndpointDisplays();
        });

        // Step 1: Perform Login
        async function performLogin() {
            const username = document.getElementById('username').value;
            const password = document.getElementById('password').value;
            
            if (!username || !password) {
                showGlobalStatus('Please enter both username and password', 'error');
                return;
            }

            setLoginLoading(true);
            showGlobalStatus('Authenticating with Okta...', 'info');

            try {
                const authUrl = oktaConfig.authApiEndpoint;
                
                const response = await fetch(authUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({
                        username: username,
                        password: password,
                        options: {
                            multiOptionalFactorEnroll: false,
                            warnBeforePasswordExpired: false
                        }
                    })
                });

                if (!response.ok) {
                    const errorData = await response.json();
                    throw new Error(errorData.errorSummary || `HTTP ${response.status}`);
                }

                const data = await response.json();
                
                if (data.status === 'SUCCESS') {
                    sessionToken = data.sessionToken;
                    showStep2Success();
                } else {
                    throw new Error(`Authentication failed: ${data.status}`);
                }

            } catch (error) {
                showGlobalStatus(`Login failed: ${error.message}`, 'error');
            } finally {
                setLoginLoading(false);
            }
        }

        // Step 2: Show session token success
        function showStep2Success() {
            updateProgress(2);
            document.getElementById('sessionTokenDisplay').textContent = sessionToken;
            showStep(2);
            showGlobalStatus('✅ Login successful! Session token retrieved.', 'success');
        }

        // Step 3: Start iframe PKCE Flow
        async function startIframePKCE() {
            updateProgress(3);
            showStep(3);
            showGlobalStatus('Starting iframe PKCE authorization flow...', 'info');

            try {
                // Generate PKCE parameters
                pkceParams.codeVerifier = generateCodeVerifier();
                pkceParams.codeChallenge = await generateCodeChallenge(pkceParams.codeVerifier);
                pkceParams.state = generateRandomString();
                pkceParams.nonce = generateRandomString();

                // Build authorization URL
                const authUrl = new URL(oktaConfig.authEndpoint);
                const params = {
                    'client_id': oktaConfig.clientId,
                    'response_type': 'code',
                    'scope': 'openid profile email',
                    'redirect_uri': oktaConfig.redirectUri,
                    'state': pkceParams.state,
                    'nonce': pkceParams.nonce,
                    'code_challenge': pkceParams.codeChallenge,
                    'code_challenge_method': 'S256',
                    'sessionToken': sessionToken
                };

                Object.keys(params).forEach(key => {
                    authUrl.searchParams.append(key, params[key]);
                });

                // Show iframe container
                document.getElementById('iframeContainer').classList.remove('hidden');
                
                // Load authorization URL in iframe
                const iframe = document.getElementById('oauthIframe');
                iframe.src = authUrl.toString();

                // Update status
                document.getElementById('iframeStatus').innerHTML = `
                    <span class="spinner"></span>
                    <span>Loading OAuth authorization in iframe...</span>
                `;

                // Start monitoring iframe for callback
                startIframeMonitoring();

            } catch (error) {
                showGlobalStatus(`iframe PKCE flow error: ${error.message}`, 'error');
            }
        }

        // Monitor iframe for OAuth callback
        function startIframeMonitoring() {
            const iframe = document.getElementById('oauthIframe');
            let attempts = 0;
            const maxAttempts = 60; // 60 seconds timeout

            iframeMonitorInterval = setInterval(() => {
                attempts++;
                
                try {
                    // Try to access iframe URL
                    const iframeUrl = iframe.contentWindow.location.href;
                    
                    // Check if we got redirected to callback with code
                    if (iframeUrl.includes('code=')) {
                        clearInterval(iframeMonitorInterval);
                        
                        const urlParams = new URLSearchParams(iframeUrl.split('?')[1]);
                        const code = urlParams.get('code');
                        const state = urlParams.get('state');
                        
                        if (code && state === pkceParams.state) {
                            document.getElementById('iframeStatus').innerHTML = `
                                <div class="status success">✅ Authorization code captured from iframe!</div>
                            `;
                            exchangeTokens(code, pkceParams.codeVerifier);
                        } else {
                            throw new Error('Invalid authorization response');
                        }
                    }
                    
                } catch (e) {
                    // Cross-origin error is expected while iframe is on Okta domain
                    // We'll continue monitoring
                }
                
                // Timeout after maxAttempts
                if (attempts >= maxAttempts) {
                    clearInterval(iframeMonitorInterval);
                    document.getElementById('iframeStatus').innerHTML = `
                        <div class="status error">⏰ Timeout waiting for authorization. Please try again.</div>
                    `;
                }
                
                // Update status every 5 seconds
                if (attempts % 5 === 0) {
                    document.getElementById('iframeStatus').innerHTML = `
                        <span class="spinner"></span>
                        <span>Waiting for OAuth authorization... (${attempts}s)</span>
                    `;
                }
                
            }, 1000);
        }

        // Exchange tokens
        async function exchangeTokens(code, codeVerifier) {
            try {
                updateProgress(4);
                showGlobalStatus('Exchanging authorization code for tokens...', 'info');

                const tokenResponse = await fetch(oktaConfig.tokenEndpoint, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Accept': 'application/json'
                    },
                    body: new URLSearchParams({
                        'grant_type': 'authorization_code',
                        'client_id': oktaConfig.clientId,
                        'code': code,
                        'redirect_uri': oktaConfig.redirectUri,
                        'code_verifier': codeVerifier
                    })
                });

                if (!tokenResponse.ok) {
                    const errorText = await tokenResponse.text();
                    throw new Error(`Token exchange failed: ${tokenResponse.status} - ${errorText}`);
                }

                const tokenData = await tokenResponse.json();
                tokens.accessToken = tokenData.access_token;
                tokens.idToken = tokenData.id_token;

                showFinalResults();

            } catch (error) {
                showGlobalStatus(`Token exchange error: ${error.message}`, 'error');
            }
        }

        // Show final results
        function showFinalResults() {
            updateProgress(4, true);
            showStep('finalResults');
            
            document.getElementById('finalAccessToken').textContent = tokens.accessToken;
            document.getElementById('finalIdToken').textContent = tokens.idToken;
            document.getElementById('tokenForHeader').textContent = tokens.accessToken;
            
            showGlobalStatus('🎉 PKCE OpenID flow completed successfully!', 'success');
        }

        // Utility functions
        function updateProgress(step, completed = false) {
            for (let i = 0; i <= 4; i++) {
                const elem = document.getElementById(`step${i}-progress`);
                if (elem) {
                    elem.classList.remove('active', 'completed');
                    if (i < step || (i === step && completed)) {
                        elem.classList.add('completed');
                    } else if (i === step) {
                        elem.classList.add('active');
                    }
                }
            }
            currentStep = step;
        }

        function showStep(stepId) {
            document.querySelectorAll('.step').forEach(step => {
                step.classList.remove('active');
                step.classList.add('hidden');
            });
            
            const targetStep = typeof stepId === 'string' ? 
                document.getElementById(stepId) : 
                document.getElementById(`step${stepId}`);
            
            if (targetStep) {
                targetStep.classList.remove('hidden');
                targetStep.classList.add('active');
            }
        }

        function setLoginLoading(loading) {
            const spinner = document.getElementById('loginSpinner');
            const text = document.getElementById('loginText');
            const button = document.querySelector('#step1 button');
            
            if (loading) {
                spinner.classList.remove('hidden');
                text.textContent = 'Authenticating...';
                button.disabled = true;
            } else {
                spinner.classList.add('hidden');
                text.textContent = '🚀 Login to Okta';
                button.disabled = false;
            }
        }

        function showGlobalStatus(message, type) {
            const statusDiv = document.getElementById('globalStatus');
            const statusText = document.getElementById('globalStatusText');
            
            statusText.textContent = message;
            statusDiv.className = `status ${type}`;
            statusDiv.classList.remove('hidden');
            
            if (type === 'success') {
                setTimeout(() => {
                    statusDiv.classList.add('hidden');
                }, 5000);
            }
        }

        function copyToken(type) {
            const token = type === 'access' ? tokens.accessToken : tokens.idToken;
            if (!token) return;

            navigator.clipboard.writeText(token).then(() => {
                showGlobalStatus(`${type} token copied to clipboard!`, 'success');
            });
        }

        function copyAuthHeader() {
            const header = `Authorization: Bearer ${tokens.accessToken}`;
            navigator.clipboard.writeText(header).then(() => {
                showGlobalStatus('Authorization header copied to clipboard!', 'success');
            });
        }

        function decodeToken(type) {
            console.log('decodeToken called with type:', type);
            console.log('Current tokens:', tokens);
            
            const token = type === 'access' ? tokens.accessToken : tokens.idToken;
            
            if (!token) {
                showGlobalStatus(`No ${type} token available to decode`, 'error');
                return;
            }

            try {
                console.log('Attempting to decode token:', token.substring(0, 50) + '...');
                
                const parts = token.split('.');
                if (parts.length !== 3) {
                    throw new Error('Invalid JWT format - token must have 3 parts');
                }

                // Decode header and payload
                const header = JSON.parse(atob(parts[0]));
                const payload = JSON.parse(atob(parts[1]));

                console.log('Decoded header:', header);
                console.log('Decoded payload:', payload);

                const decoded = {
                    tokenType: type.toUpperCase() + ' TOKEN',
                    header: header,
                    payload: payload,
                    claims: {
                        issuer: payload.iss,
                        audience: payload.aud,
                        subject: payload.sub,
                        clientId: payload.cid,
                        scopes: payload.scp,
                        issued: new Date(payload.iat * 1000).toLocaleString(),
                        expires: new Date(payload.exp * 1000).toLocaleString(),
                        authTime: payload.auth_time ? new Date(payload.auth_time * 1000).toLocaleString() : 'N/A'
                    }
                };

                // Add ID token specific claims
                if (type === 'id') {
                    decoded.claims.name = payload.name || 'N/A';
                    decoded.claims.email = payload.email || 'N/A';
                    decoded.claims.preferredUsername = payload.preferred_username || 'N/A';
                }

                document.getElementById('decodedDisplay').textContent = JSON.stringify(decoded, null, 2);
                document.getElementById('decodedTokens').classList.remove('hidden');
                
                showGlobalStatus(`✅ ${type.toUpperCase()} token decoded successfully!`, 'success');

            } catch (error) {
                console.error('Token decode error:', error);
                showGlobalStatus(`Error decoding ${type} token: ${error.message}`, 'error');
                
                // Show raw token for debugging
                document.getElementById('decodedDisplay').textContent = `
ERROR DECODING TOKEN:
${error.message}

RAW TOKEN:
${token}

TOKEN PARTS:
${token.split('.').map((part, i) => `Part ${i + 1}: ${part}`).join('\n')}
                `;
                document.getElementById('decodedTokens').classList.remove('hidden');
            }
        }

        // PKCE utility functions
        function generateCodeVerifier() {
            const array = new Uint8Array(32);
            crypto.getRandomValues(array);
            return base64URLEncode(array);
        }

        async function generateCodeChallenge(verifier) {
            const encoder = new TextEncoder();
            const data = encoder.encode(verifier);
            const digest = await crypto.subtle.digest('SHA-256', data);
            return base64URLEncode(new Uint8Array(digest));
        }

        function base64URLEncode(array) {
            return btoa(String.fromCharCode.apply(null, array))
                .replace(/\+/g, '-')
                .replace(/\//g, '_')
                .replace(/=/g, '');
        }

        function generateRandomString() {
            const array = new Uint8Array(16);
            crypto.getRandomValues(array);
            return base64URLEncode(array);
        }

        // Cleanup on page unload
        window.addEventListener('beforeunload', function() {
            if (iframeMonitorInterval) {
                clearInterval(iframeMonitorInterval);
            }
        });
    </script>
</body>
</html>
